from flask import session,render_template,current_app,jsonify,g,request
# 导入蓝图对象
from . import news_blue
# 导入数据库模型
from info.models import User, Category,News, Comment,CommentLike
# 导入状态码
from info.utils.response_code import RET
# 导入常量包和数据库对象
from info import constants,db
# 导入封装的功能代码
from info.utils.commons import get_user,rank_list


@news_blue.route("/")
@rank_list
@get_user
def index():
    """
    项目首页数据加载
        一、首页登录状态
        1.检查登录状态
        2.使用session对象,congredis中获取用户信息,否则显示登录注册入口
        3.根据user_id,查询mysql,获取用户数据
        4.传给前段模板
        二、新闻分类
        1.查询数据库,获取新闻分类数据
        2.判断查询结果是否为空
        3.便利查询结果使用模型类中的to_dict()方法
        4.将新闻分类列表添加到data字典中传入模板
        三、点击排行
        1.查询排序结果
        2.将查询结果便利,添加到列表容器中
        3.将列表容器添加到data字典中传给模板

    :return:
    """

    # 使用g对象调用当前用户对象
    user = g.user

    # 实现新闻分类
    # 1.查询数据库
    try:
        categorys = Category.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询分类错误/")
    # 2.检查查询结果
    if not categorys:
        return jsonify(errno=RET.DATAEXIST,errmsg="新闻分类结果为空")
    # 3.定义list容器
    category_list = []
    # 4.便利查询结果
    for category in categorys:
       category_list.append(category.to_dict())


    # 使用g对象调用点击排行
    ranking_list = g.rank_list

    # 定义字典,用来存储u需要返回给模板的数据
    data = {
        "user_info":user.to_dict() if user else None,
        "category_list":category_list,
        "ranking_list":ranking_list
    }

    return render_template("news/index.html", data = data)

@news_blue.route("/favicon.ico")
def favicon():
    """
    重定向主页的ico
    :return:
    """
    # 发送给浏览器
    return current_app.send_static_file("news/favicon.ico")

@news_blue.route("/news_list")
def new_list():
    """
    实现获取新闻列表数据
    1.接收参数:cid, page(否必须), per_page(否必须)
    2.检查参数
    3.实现需求
    4.返回参数
    :return:
    """
    cid = request.args.get("cid",1)
    page = request.args.get("page",1)
    per_page = request.args.get("per_page",constants.HOME_PAGE_MAX_NEWS)
    # 将参数的数据类型转换成int
    try:
        cid, page, per_page = int(cid), int(page), int(per_page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数类型错误")
    # 3.根据cid查询数据库
    # 先定义一个容器,封装代码,用来判断"最新"还是有分类
    filter = []
    if cid > 1:
        filter.append(News.category_id == cid)
    try:
        paginate = News.query.filter(*filter).order_by(News.create_time.desc()).paginate(page,per_page,False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询分页错误")
    news_list = []
    for news in paginate.items:
        news_list.append(news.to_dict())
    return jsonify(errno = RET.OK, errmsg="OK",
                   cid=cid,
                   totalPage=paginate.pages,
                   currentPage=paginate.page,
                   newsList=news_list)


@news_blue.route("/<int:news_id>")
@rank_list
@get_user
def detail(news_id):
    """
    定义新闻详情页的接口
    :param new_is:
    :return:
    """
    # 使用g对象调用当前用户对象
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")


    # 使用g对象调用点击排行
    ranking_list = g.rank_list

    # 根据news_id查询新闻
    try:
        news = News.query.filter(News.id == news_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻出错")
    if not news:
        return jsonify(errno=RET.DATAEXIST, errmsg="新闻不存在")

    # 新闻点击量+1
    news.clicks += 1
    try:
        db.session.add(news)
        db.session.commit()
    except Exception as e:
        return jsonify(errno=RET.DBERR,errmsg="新闻点击量更新失败")

    # # 新闻是否被收藏
    # collection = False
    # if news in user.collection_news:
    #     collection = True
    # else:
    #     collection = False
    #
    # # 根据news_id反向查询author信息
    # author = User.query.filter(User.id == news.user_id).first()
    # # print(author.to_dict()["id"])
    # # print(author.to_dict()["followers_count"])
    #
    # # 查询是否关注该作者
    # follower = False
    # if user:
    #     if user in author.followers:
    #         follower = True

    # 当前登录用户是否关注当前新闻作者
    followed = False
    # 判断用户是否收藏过该新闻
    collected = False
    if g.user:
        if news in g.user.collection_news:
            collected = True
        if news.user.followers.filter(User.id == g.user.id).count() > 0:
            followed = True

    # 查询新闻评论
    comments = []
    # 查询评论
    try:
        comments = Comment.query.filter(Comment.news_id == news_id,).order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询评论失败")
    # 遍历评论
    comment_list = []
    comment_child_list = []
    for comment in comments:
        if comment.parent_id:
            comment_child_list.append(comment.to_dict())
            # print(comment.to_dict()["id"])

        else:
            comment_list.append(comment.to_dict())

    # 查询点赞
    ups = CommentLike.query.filter(user.id == CommentLike.user_id).all()
    # 是否有点赞
    # 遍历
    up_list = []
    if ups:
        for up in ups:
            up_list.append(up.to_dict())
    print(up_list)

    data = {
        "news":news.to_dict(),
        "user_info": user.to_dict() if user else None,
        "ranking_list": ranking_list,
        "collection":collected,
        "followered":followed,
        "comment_list":comment_list,
        "comment_child_list":comment_child_list,
        "up_list":up_list
    }
    return render_template("news/detail.html",data=data)


@news_blue.route("/news/news_collect", methods=["POST"])
@get_user
def collect():
    """
    实现收藏/取消收藏的接口函数
    :return:
    """
    # 1.接受参数
    news_id = request.json.get("news_id")
    action = request.json.get("action")
    # 2 检查参数
    if not all([news_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数缺失")
    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数类型错误")
    if action not in ('collect', 'cancel_collect'):
        return jsonify(errno=RET.PARAMERR, errmsg="参数值错误")

    # 3.功能实现
    # 使用g对象调用当前用户对象
    user = g.user
    # 检查用户是否登录
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    # 查询新闻
    try:
        new = News.query.filter(News.id == news_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="新闻查询错误")
    # 判断新闻是否存在
    if not new:
        return jsonify(errno=RET.DATAEXIST, errmsg="新闻数据不存在")

    # 执行收藏/取消收藏操作
    if action == "collect":
        if new not in user.collection_news:
            user.collection_news.append(new)

    elif action == "cancel_collect":
        user.collection_news.remove(new)

    # 更新到数据库
    try:
        # db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="用户更新错误")
    return jsonify(errno=RET.OK, errmsg="OK")


@news_blue.route("/news/author_follow", methods=["POST"])
@get_user
def follow():
    """
    实现关注/取消关注作者的接口
    url:/news/author_follow
    method:post
    params1:author_id:作者id
    params2:action:["followed":取消关注; "followtion":关注]
    :return:
    errno:响应状态码
    errmsg:响应说明
    """
    # 1.接收参数:
    author_id = request.json.get("author_id")
    action = request.json.get("action")
    # 2.检查参数
    try:
        author_id = int(author_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数类型错误")
    if action not in ("followtion", "cancel_follow"):
        return jsonify(errno=RET.PARAMERR, errmsg="参数范围错误")
    # 3.功能实现
    # 使用g对象调用当前用户对象
    user = g.user
    # 检查用户是否登录
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    # 查询作者
    try:
        author = User.query.filter(User.id == author_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="作者查询错误")
    # 判断新闻是否存在
    if not author:
        return jsonify(errno=RET.DATAEXIST, errmsg="新闻数据不存在")
    print(author)
        # 执行关注/取消关注操作
    if action == "followtion":
        if author not in user.followers:
            author.followers.append(user)

    elif action == "cancel_follow":
        author.followers.remove(user)

    # 更新到数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="用户更新错误")

    return jsonify(errno=RET.OK, errmsg="OK")


@news_blue.route("/news/news_comment", methods=["POST"])
@get_user
def set_comment():
    """
    评论新闻的后端实现
    请求方式:post
    格式:json
    参数:
        news_id: int 新闻id
        comment: string 评论内容
        parent_id: int 非必须 被回复评论的id
    :return:
        errno: int 错误码
        errmsg: string 错误信息
    """
    # 判断用户登录情况
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    # 1.获取参数
    news_id = request.json.get("news_id")
    comment_str = request.json.get("comment")
    parent_id = request.json.get("parent_id")
    # 2.检查参数
    if not all([news_id, comment_str]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")
    try:
        news_id = int(news_id)
    except Exception as e:
        return jsonify(errno=RET.PARAMERR, reemsg="参数类型错误")
    # 获取当前新闻
    try:
        news = News.query.filter(News.id == news_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取新闻数据错误")
    if not news:
        return jsonify(errno=RET.DATAEXIST, errmsg="新闻不存在")

    # 保存评论
    comment = Comment()
    comment.user_id = user.id
    comment.news_id = news_id
    comment.content = comment_str
    if parent_id:
        comment.parent_id = parent_id

    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="评论保存失败")
    # 返回相应
    return jsonify(errno=RET.OK, errmsg="OK", data=comment.to_dict())


@news_blue.route("/comment_up", methods=["POST"])
@get_user
def comment_up():
    """
        点赞的后端实现
        请求方式:post
        格式:json
        参数:
            comment_id: int 评论id
            active: string ["up","concel_up"]
        :return:
            errno: int 错误码
            errmsg: string 错误信息
        """
    # 判断用户登录情况
    user = g.user
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    pass
    # 接收参数
    comment_id = request.json.get("comment_id")
    active = request.json.get("active")
    # 检查参数
    try:
        comment_id = int(comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数类型错误")
    if active not in ["up","concel_up"]:
        return jsonify(errno=RET.PARAMERR, errmsg="参数范围错误")

    # # 查询是否为为重复点赞
    up_comment = CommentLike.query.filter(CommentLike.user_id == user.id, CommentLike.comment_id == comment_id).first()
    # print(up_comment)
    # if up_comment:
    #     return jsonify(errno=RET.DATAEXIST, errmsg="不允许重复点赞")

    # 查询评论
    comment = Comment.query.filter(Comment.id == comment_id).first()
    if not comment:
        return jsonify(errno=RET.NODATA, errmsg="评论不存在")
    print(comment.like_count)

    # 评论点赞对象
    comment_up = CommentLike()
    comment_up.comment_id = comment_id
    comment_up.user_id = user.id



    # 添加到数据库
    try:
        # 评论中点赞改变
        if active == "up":
            comment.like_count += 1
            db.session.add(comment_up)
        else:
            # 在点赞表中删除的一定是已经存在的点赞信息而不是新创建的额数据
            db.session.delete(up_comment)
            comment.like_count -= 1
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="点赞保存失败")

    return jsonify(errno=RET.OK, errmsg="OK")

